#pragma once
#include "../mqcommon/helper.hpp"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/mq_msg.pb.h"
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>
#include <mutex>
#include <sstream>

namespace wzf
{
    struct MsgQueue
    {
        using ptr = std::shared_ptr<MsgQueue>;
        std::string name;
        DeliveryMode durable;
        bool exclusive; //是否独占
        bool auto_delete; //自动删除
        std::unordered_map<std::string, std::string> args; //其他参数

        MsgQueue(){}
        MsgQueue(const std::string& qname, DeliveryMode qdurable, bool qexclusive, bool qauto_delete,
            const std::unordered_map<std::string, std::string>& qargs)
            : name(qname), durable(qdurable), exclusive(qexclusive), auto_delete(qauto_delete), args(qargs)
        {}

        void SetArgs(const std::string& str_args) //数据库中 key=value，函数目的，解析数据库中的字符串
        {
            std::vector<std::string> sub_args;
            StrHelper::split(str_args, "&", sub_args);
            for(auto& str : sub_args)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string val = str.substr(pos + 1);
                args.insert({key, val});
            }
        }
        std::string GetArgs() //将args内容序列化后返回一个字符串，便于存储到数据库中
        {
            std::string result;
            for(auto cur = args.begin(); cur != args.end(); ++cur)
            {
                result += cur->first + "=" + cur->second + "&";
            }
            return result;
        }
    };

    //持久化（磁盘）管理类
    class MsgQueueMapper
    {
    public:
        using ptr = std::shared_ptr<MsgQueueMapper>;
        MsgQueueMapper(const std::string& dbfile)
            : _sql_helper(dbfile)
        {
            std::string path = FileHelper::getParentDirectory(dbfile); 
            FileHelper::createDirectory(path);          //创建父目录
            assert(_sql_helper.open());
            CreateTable();
        }
        void CreateTable()
        {
            std::string create_sql = "create table if not exists queue_table(\
                name varchar(32) primary key, \
                durable int, \
                exclusive int, \
                auto_delete int, \
                args varchar(128));";
            assert(_sql_helper.exec(create_sql, nullptr, nullptr));
        }
        void RemoveTable()
        {
            std::string drop_sql = "drop table if exists queue_table";
            assert(_sql_helper.exec(drop_sql, nullptr, nullptr));
        }

        bool Insert(const MsgQueue::ptr& ptr)
        {
            std::stringstream insert_sql;
            insert_sql << "insert into queue_table values(";
            insert_sql << "'" << ptr->name << "',"; 
            insert_sql << ptr->durable << ",";
            insert_sql << ptr->exclusive << ",";
            insert_sql << ptr->auto_delete << ",";
            insert_sql << "'" << ptr->GetArgs() << "');";
            // DLOG("生成的 SQL 语句: %s", ss.str().c_str());
            return _sql_helper.exec(insert_sql.str(), nullptr, nullptr);
        }

        bool Remove(const std::string& name)
        {
            std::stringstream remove_sql;
            remove_sql << "delete from queue_table where name=";
            remove_sql << "'" << name << "';";
            return _sql_helper.exec(remove_sql.str(), nullptr, nullptr);  //这里也不会false。
        }

        using QueueMap = std::unordered_map<std::string, MsgQueue::ptr>;
        QueueMap Recovery() //name和交换机对象的映射
        {
            QueueMap result;
            std::string select_sql = "select * from queue_table";
            _sql_helper.exec(select_sql, SelectCallBack, &result);
            return result;
        }
    private:
        static int SelectCallBack(void* arg, int col, char** row, char** fields)
        {
            QueueMap* result = static_cast<QueueMap*>(arg);
            auto ptr = std::make_shared<MsgQueue>();

            ptr->name = row[0];
            ptr->durable = static_cast<DeliveryMode>(std::stoi(row[1]));
            ptr->exclusive = static_cast<bool>(std::stoi(row[2]));
            ptr->auto_delete = static_cast<bool>(std::stoi(row[3]));
            if(row[4]) ptr->SetArgs(row[4]);
            result->insert({ptr->name, ptr});

            return 0;
        }
    private:
        SqliteHelper _sql_helper;
    };

    //队列内存数据管理类
    class MsgQueueManager
    {
    public:
        MsgQueueManager(const std::string& dbfile)
            : _mapper(dbfile)
        {
            _msg_queues = _mapper.Recovery();
        }
        //声明队列
        void DeclareQueue(const std::string& name, DeliveryMode durable, bool exclusive, bool auto_delete, 
            const std::unordered_map<std::string, std::string>& args)
        {
            std::unique_lock<std::mutex> lock(_mutex); 
            if(_msg_queues.count(name) == false)
            {
                auto ptr = std::make_shared<MsgQueue>(name, durable, exclusive, auto_delete, args);
                _msg_queues.insert({name, ptr});
                if(ptr->durable == DeliveryMode::DURABLE)
                {
                    _mapper.Insert(ptr);
                    DLOG("_mapper.Insert(ptr)");
                } 
            }
        }
        //删除指定队列
        void DeleteQueue(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if(it != _msg_queues.end())
            {
                _msg_queues.erase(name);
                if(it->second->durable == DeliveryMode::DURABLE) _mapper.Remove(name);
            }
        }
        //查指定队列的数据
        MsgQueue::ptr SelectQueue(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _msg_queues.find(name);
            if(it != _msg_queues.end())
            {
                return it->second;
            }
            return nullptr;
        }
        // const MsgQueueMapper::QueueMap& allQueue() //这样返回不用拷贝 但是也是不安全的
        MsgQueueMapper::QueueMap allQueue() 
        {                                            //线程安全保证的是，读取完毕之前，是安全的，比如说这里读取也就是不能改变它
            std::unique_lock<std::mutex> lock(_mutex);  //但是这个锁只能安全下面一行
            return _msg_queues;                     //换句话说在对共享资源进程读取或者修改的时候，必须在锁内
        } 
        bool Exists(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_msg_queues.count(name))
                return true;
            return false;
        }
        size_t Size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues.size();
        }
        void Clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.RemoveTable();
            _msg_queues.clear();
        }
    private:
        std::mutex _mutex;
        MsgQueueMapper _mapper;
        MsgQueueMapper::QueueMap _msg_queues;
    };
}